package grid;

import hdgeom.primitives.TrianglePreCalc;

import java.util.ArrayList;
import java.util.Collections;

import processing.core.PVector;

public class Grid3DScan {
	final static int DISJOINT=0;
	final static int INTERSECT=1;
	final static int SAME_PLANE=2;


public static void scanMeshDistanceAll(float[] xC, float[] yC, float[] zC,
		int[] faces, float x1, float y1, float z1, int nX, int nY, int nZ,
		float dim, float[] result){
	for (int i=0;i<result.length;i++){
		result[i]=100;
	}
	float cValue = 0;
	TrianglePreCalc tri;
	float[] triBounds=new float[6];
	for (int i = 0; i < faces.length; i+=3) {
		if (i % 100000 == 0) {
			System.out.println(i + "/" + faces.length);
		}
		int i1=faces[i];
		int i2=faces[i+1];
		int i3=faces[i+2];
		tri = new TrianglePreCalc(xC[i1],yC[i1],zC[i1],xC[i2],yC[i2],zC[i2],xC[i3],yC[i3],zC[i3]);
		
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				for (int z = 0; z < nZ; z++) {
					float cellX = x1+x*dim;
					float cellY =y1+y*dim;
					float cellZ = z1+z*dim;
					float planeDist = (float)Math.abs(tri.getDistancePlane(cellX,cellY,cellZ));
					int index = x * nY * nZ + y * nZ + z;
					cValue =result[index];
					if (planeDist < cValue) {
						//
						float cDist = (float) tri.getDistance(cellX, cellY, cellZ);
						if (cDist < cValue) {
							result[index]=cDist;
						}
					}
				}
			}
		}
	}
}
public static void scanMeshDistanceContinue(float[] xC, float[] yC, float[] zC,
		int[] faces, float x1, float y1, float z1, int nX, int nY, int nZ,
		float dim,float offset, float[] result){
	float cValue = 0;
	TrianglePreCalc tri;
	float[] triBounds=new float[6];
	for (int i = 0; i < faces.length; i+=3) {
		if (i % 100000 == 0) {
			System.out.println("scanned triangles: "+i + "/" + faces.length);
		}
		
		int i1=faces[i];
		int i2=faces[i+1];
		int i3=faces[i+2];
		tri = new TrianglePreCalc(xC[i1],yC[i1],zC[i1],xC[i2],yC[i2],zC[i2],xC[i3],yC[i3],zC[i3]);
		tri.calculateBounds(triBounds);
		triBounds[0]-=offset;
		triBounds[1]-=offset;
		triBounds[2]-=offset;
		triBounds[3]+=offset;
		triBounds[4]+=offset;
		triBounds[5]+=offset;
		
		int cx1 = (int)((triBounds[0]-x1)/dim) - 1;
		int cy1 = (int)((triBounds[1]-y1)/dim) - 1;
		int cz1 = (int)((triBounds[2]-z1)/dim) - 1;
		cx1 = Math.max(0, cx1);
		cy1 = Math.max(0, cy1);
		cz1 = Math.max(0, cz1);
		int cx2 = (int)((triBounds[3]-x1)/dim) + 2;
		int cy2 =  (int)((triBounds[4]-y1)/dim) + 2;
		int cz2 = (int)((triBounds[5]-z1)/dim) + 2;
		cx2 = Math.min(nX, cx2);
		cy2 = Math.min(nY, cy2);
		cz2 = Math.min(nZ, cz2);
		
		for (int x = cx1; x < cx2; x++) {
			for (int y = cy1; y < cy2; y++) {
				for (int z = cz1; z < cz2; z++) {
					float cellX = x1+x*dim;
					float cellY =y1+y*dim;
					float cellZ = z1+z*dim;
					float planeDist =  (float)Math.abs(tri.getDistancePlane(cellX,cellY,cellZ));
					
					int index = x * nY * nZ + y * nZ + z;

					cValue =result[index];
					//if (planeDist < cValue) {
						
						float cDist = (float)tri.getDistance(cellX, cellY, cellZ);
						result[index]=Math.min(cDist, cValue);
						
						//}
				}
			}
		}
	}
}
public static void scanMeshDistance(float[] xC, float[] yC, float[] zC,
		int[] faces, float x1, float y1, float z1, int nX, int nY, int nZ,
		float dim,float offset, float[] result){
		int maxD=nX*nY*nZ;
		for (int i=0;i<result.length;i++){
			result[i]=maxD;
		}
		scanMeshDistanceContinue(xC,yC,zC,faces,x1,y1,z1,nX,nY,nZ,dim,offset,result);
		
}

	public static void scanMeshBinary2(float[] xC, float[] yC,
			float[] zC, int[] faces, float x1, float y1, float z1, int nX,
			int nY, int nZ, float dim, float[] result) {
		float offset = dim;
		int maxD = nX * nY * nZ;
		int nYZ=nY*nZ;
		for (int i = 0; i < result.length; i++) {
			result[i] = 1;
		}
		float zStart=z1-dim;
		float cValue = 0;
		TrianglePreCalc tri;
		float[] intersection = new float[3];
		float[] triBounds = new float[6];
		for (int i = 0; i < faces.length; i += 3) {
			if (i % 100000 == 0) {
				System.out.println("scanned triangles: " + i + "/"
						+ faces.length);
			}

			int i1 = faces[i];
			int i2 = faces[i + 1];
			int i3 = faces[i + 2];
			tri = new TrianglePreCalc(xC[i1], yC[i1], zC[i1], xC[i2], yC[i2],
					zC[i2], xC[i3], yC[i3], zC[i3]);
			tri.calculateBounds(triBounds);
			triBounds[0] -= offset;
			triBounds[1] -= offset;
			triBounds[2] -= offset;
			triBounds[3] += offset;
			triBounds[4] += offset;
			triBounds[5] += offset;

			int cx1 = (int) ((triBounds[0] - x1) / dim) - 1;
			int cy1 = (int) ((triBounds[1] - y1) / dim) - 1;

			cx1 = Math.max(0, cx1);
			cy1 = Math.max(0, cy1);

			int cx2 = (int) ((triBounds[3] - x1) / dim) + 2;
			int cy2 = (int) ((triBounds[4] - y1) / dim) + 2;

			cx2 = Math.min(nX, cx2);
			cy2 = Math.min(nY, cy2);

			for (int x = cx1; x < cx2; x++) {
				for (int y = cy1; y < cy2; y++) {
					float oX = x1 + x * dim;
					float oY = y1 + y * dim;
					int check = tri.triIntersect(oX, oY, zStart, 0, 0, 1,
							intersection);
					if (check==tri.INTERSECT){
						int endZ=(int)((intersection[2]-z1)/dim);
						for (int z=0;z<endZ;z++){
							int index=x*nYZ+y*nZ +z;
						if (result[index]==0)
							result[index]=1;
						
						else
							result[index]=0;
						
						}
					}
				}
			}
		}
		
	}
	
public  static ArrayList<PVector> scanMeshBinary(float[] xC, float[] yC, float[] zC,
		int[] faces, float x1, float y1, float z1, int nX, int nY, int nZ,
		float dim, float[] result) {
	ArrayList<PVector>intersectors=new ArrayList<PVector>();
	float[] intersection = new float[3];
	ArrayList<Float> intersections = new ArrayList<Float>();
	TrianglePreCalc triangle=new TrianglePreCalc();
	for (int x = 0; x < nX; x++) {
		//System.out.println("process: "+x+"/"+nX);
		for (int y = 0; y < nY; y++) {
			intersections.clear();
			// ray in z-direction
			float oX = x * dim + x1;
			float oY = y * dim + y1;
			float oZ = z1;
			// collect all intersections
			for (int i = 0; i < faces.length; i += 3) {
				int i1 = faces[i];
				int i2 = faces[i + 1];
				int i3 = faces[i + 2];
				int check = triangle.triIntersect(oX, oY, oZ, 0, 0, 1, xC[i1],
						yC[i1], zC[i1], xC[i2], yC[i2], zC[i2], xC[i3],
						yC[i3], zC[i3], intersection);
				if (check == INTERSECT) {
					intersections.add(intersection[2]);
					intersectors.add(new PVector(oX,oY,(float)intersection[2]));
				}
			}
			Collections.sort(intersections);
			int startI = 1;
			if (intersections.size() % 2 == 0)
			startI = 0;
			for (int i = startI; i < intersections.size() - 1; i += 2) {
				int zStart = (int) ((intersections.get(i) - z1) / dim);
				int zEnd = (int) ((intersections.get(i + 1) - z1) / dim);
				for (int cZ = zStart; cZ < zEnd; cZ++) {
					int index = x * nY * nZ + y * nZ + cZ;
					result[index] = 1;
				}

			}
		}
	}
	return intersectors;
}


}
